const compileUtil = {
    text(node,expr,vm){
        let value
        if(expr.indexOf('{{') !== -1){
            value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
                // console.log(args)
                new Watcher(vm,args[1],()=>{
                    this.updater.textUpdater(node,this.getContentVal(expr,vm))
                })
                return this.getValue(args[1],vm)
            })
        }else{
            new Watcher(vm,expr,(newVal)=>{
                this.updater.textUpdater(node,newVal)
            })
            value = this.getValue(expr,vm)
        }
        // const value = this.getValue(expr,vm)
        // const value = vm.$data[expr]
        this.updater.textUpdater(node,value)
    },
    html(node,expr,vm){
        const value = this.getValue(expr,vm)
        new Watcher(vm,expr,(newVal)=>{
            this.updater.htmlUpdater(node,newVal)
        })
        this.updater.htmlUpdater(node,value)
    },
    model(node,expr,vm){
        const value = this.getValue(expr,vm)
        // 绑定更新函数
        new Watcher(vm,expr,(newVal)=>{
            this.updater.modelUpdater(node,newVal)
        })

        node.addEventListener('input',(e)=>{
            // 设置值
            this.setVal(expr,vm,e.target.value)

        })
        this.updater.modelUpdater(node,value)
    },
    on(node,expr,vm,enentName){
        let fn = vm.$options.methods && vm.$options.methods[expr]
        node.addEventListener(enentName,fn.bind(vm),false)
    },
    getContentVal(expr,vm){
        return expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
            return this.getValue(args[1],vm)
        })
    },
    setVal(expr,vm,inputVal){
       return expr.split('.').reduce((obj, current) => {
            if(typeof(obj[current])!=='object') {
                obj[current] = inputVal;
            }
             return obj[current];
      }, vm.$data);
    },
    getValue(expr,vm){
        return expr.split('.').reduce((data,currentValue)=>{
            return data[currentValue]
        },vm.$data)
    },
    updater:{
        textUpdater(node,value){
            node.textContent = value
        },
        htmlUpdater(node,value){
            node.innerHTML = value
        },
        modelUpdater(node,value){
            node.value = value
        }
    }
}


class Compile {
    constructor(el, vm) {
        // 判断el是不是元素节点对象
        this.el = this.isElementNode(el) ? el : document.querySelector(el)
        //   console.log(this.el)
        this.vm = vm
        //   console.log(this.vm)
        // 获取文档对象，防止页面回流和重绘
        const fragment = this.node2Fragment(this.el)
        this.compile(fragment)
        // 2.追加所有的子元素
        this.el.appendChild(fragment)
    }
    // <h2>
    //         {{person.name}}--{{person.age}}
    //     </h2>
    compile(fragment){
        // 获取到每一个子节点
        // console.log(fragment.childNodes)
        // const childNodes = fragment.childNodes
        const childNodes = [...fragment.childNodes]
        childNodes.forEach(child => {
            if(this.isElementNode(child)){
                // 元素节点
                // console.log('元素节点',child)
                this.compileElement(child)

            }else{
                // console.log('文本节点',child)
                this.compileText(child)
            }
            // 元素节点还有子节点
            if(child.childNodes && child.childNodes.length){
                this.compile(child)
            }
        });
    }
    compileElement(node){
        const attributes = [...node.attributes]
        attributes.forEach(attr =>{
            // console.log(attr)
            const {name,value} = attr;
            // console.log(name,value)
            // console.log(this.isDirective(name))
            if(this.isDirective(name)){
                const [,directive] = name.split('-')
                // console.log(directive)
                // 更新视图
                const [dirName,eventName] =  directive.split(':')
                compileUtil[dirName](node,value,this.vm,eventName)
                // 删除v- 指令的属性
                node.removeAttribute('v-'+ directive)

            }else if(this.isEventName(name)){  // @click
                console.log(name)
                let [,eventName] = name.split('@')
                compileUtil['on'](node,value,this.vm,eventName)
                node.removeAttribute(name)
            }
        })
    
        // console.log(node.attributes)
    }
    isEventName(name){
        return name.startsWith('@')

    }
    compileText(node){
        // console.log(node.textContent)
        const content = node.textContent
        if(/\{\{(.+?)\}\}/.test(content)){
            // console.log(content)
            compileUtil['text'](node,content,this.vm)

        }

    }
    isDirective(attrName){
        return attrName.startsWith('v-')
    }
    node2Fragment(el) {
        //    const childNodes = node.childNodes
        // 创建文档对象

        const f = document.createDocumentFragment()
        let firstChild
        while (firstChild = el.firstChild) {
            f.appendChild(firstChild)
        }
        return f

    }
    // 判断是否是元素节点
    isElementNode(node) {
        return node.nodeType === 1
    }

}


class MVue {
    constructor(options) {
        this.$el = options.el
        this.$data = options.data
        this.$options = options
        if (this.$el) {
            // 1实现观察着
            new Observer( this.$data)
            // 2.实现解析器
            new Compile(this.$el, this)
            this.proxyData(this.$data)
        }
    }
    proxyData(data){
        for (const key in data) {
            Object.defineProperty(this,key,{
                get(){
                    return data[key]
                },
                set(newVal){
                    data[key] = newVal
                }
            })
        }

    }
}